/*****************************************************************************
Module :     EventLog.H
Notices:     2007.3.1 Written by Ling, Xiao-li.  Mailto: ling.xiaoli.s@gmail.com
Description: This is a resuable event log class which support multi-thread log.
			 It can log event to file, either can notify given window to fetch
			 new event.
			 
*****************************************************************************/

#pragma once
#include <afxmt.h>

namespace System
{

	namespace EventLog
	{
		//
		// BE CAREFUL:
		//	This is a Mutiple Event Source(Threads) while only One Event Process Target(CEvtLstView) mode.
		//

		// The window that m_hWndOutput points will be responsible for processing new event.
		#define WM_USERMSG_NEWEVENTLOG		( WM_APP + 100 )

		#define MAX_EVENTLOGBUFFER         500   // Max event log items in buffer
		
		#define EVTLEVEL_INFO    0
		#define EVTLEVEL_ERR     1
		#define EVTLEVEL_WARN     2  // warning

		// Set data packing to 1
		#pragma pack(push, 1)

		typedef struct
		{
			unsigned char     nEvtLevel;
			CString           sDatetime;     // Date time of event
			CString           sEvt;   
		} EVENTLOG;

		// Set data packing to 1
		#pragma pack(pop)

		class CEventLog
		{
		public:
			// if lpszFileName has no path, then log file will created in current directory.
			CEventLog(HWND hWndOutput, LPCTSTR lpszFileName, bool bFullPathFileName);
			CEventLog(HWND hWndOutput, LPCTSTR lpszFileNamePrefix);	// log by day
			~CEventLog(void);
			void SetOutputWnd(HWND hWndOutput) {  m_hWndOutput = hWndOutput; };

		protected:
			bool BuildFileName();
			bool CheckChangeLogFileName();
			inline void CloseLogFile();
		public:
			BOOL OpenLogFile();
			inline void FormatEvtString(UINT nEvtLevel, LPCTSTR lpszEvt, CString& sStr);
			void AddEvt(UINT nEvtLevel, LPCTSTR lpszEvt, bool bLog2File = true, bool bNOMsgBox=true);
			void AddEvtFormatString(UINT nEvtLevel, LPCTSTR lpszFormat, ...);
			void AddEvtFormatString(UINT nEvtLevel, LPCTSTR lpszFormat, va_list ArgList);
			void FetchEvt(EVENTLOG* pEvtList, long& nSize);
			static void DateTime(CString& sDateTime); // get system date and time

		private:
			CCriticalSection	m_csEvtLog;  // used in multiple thread environment

			HWND				m_hWndOutput;// window handle of event need to be output. If m_hWndOutput is NULL, then event only need to log to file.
			CFile				m_fileLog;
			CString				m_sFileName; // full path file name

			bool				m_bLogByDay;		// if m_bLogByDay==true, then log content will separated into mutiple log files by day.
			CString				m_sFileNamePrefix;	// if m_bLogByDay==true, m_sFileNamePrefix stores log files prefix.
			CString				m_sFilePath;		// log file path without file name, only used when m_bLogByDay==true


			SYSTEMTIME			m_stLastLog;		// last log day (system time), only used when m_bLogByDay==true
			
			// This is a round queue
			EVENTLOG			m_EvtLog[MAX_EVENTLOGBUFFER];
			unsigned int		m_nEvtHeadPtr;    // Head position for events. Round queue, 0~MAX_EVENTLOGBUFFER-1
			unsigned int		m_nEvtCnt;        // Event count
		};

		class CEventWrapper
		{
		protected:
			CEventLog*							m_pEvtLog;
		public:
			CEventWrapper() {};
			~CEventWrapper() {};

			void SetEventLog(CEventLog* pEvtLog)	{ m_pEvtLog = pEvtLog; };
			void LOGINFO(LPCTSTR lpszFormat, ...)	{ if (m_pEvtLog) { va_list params; va_start(params, lpszFormat); m_pEvtLog->AddEvtFormatString(EVTLEVEL_INFO, lpszFormat, params); va_end(params);} };
			void LOGWARN(LPCTSTR lpszFormat, ...)	{ if (m_pEvtLog) { va_list params; va_start(params, lpszFormat); m_pEvtLog->AddEvtFormatString(EVTLEVEL_WARN, lpszFormat, params); va_end(params);} };
			void LOGERR(LPCTSTR lpszFormat, ...)	{ if (m_pEvtLog) { va_list params; va_start(params, lpszFormat); m_pEvtLog->AddEvtFormatString(EVTLEVEL_ERR, lpszFormat, params); va_end(params);} };
			void LOGINFO(UINT nID, ...);

		};
	}

}



